/*
 * DoFileFilter.h
 *
 *  Created on: Oct 18, 2012
 *      Author: wtao
 */

#ifndef DOFILEFILTER_H_
#define DOFILEFILTER_H_

#include "_DoObject.h"
#include <string>
#include <sstream>
#include <map>

using namespace std;

class _DoFileFilter: public _DoObject 
{
protected:
	_DoFileFilter(const _DoFileFilter&);
	_DoFileFilter& operator=(const _DoFileFilter& obj);
public:
	_DoFileFilter();
	virtual ~_DoFileFilter();
	
	virtual void decode(std::istringstream &in, std::ostringstream &out) = 0;
};

class Ascii85Decoder : public _DoFileFilter
{
protected:
	static const std::string _suffixMark;
	
	static const int _asciiOffset;
	
	static const unsigned long _pow85[5];
	
	unsigned char mDecodedBlock[4];
	
	unsigned long mTuple;
	
	void decodeBlock(int bytes);
	
	Ascii85Decoder(const Ascii85Decoder&);
	Ascii85Decoder& operator=(const Ascii85Decoder& obj);
public:
	Ascii85Decoder();
	~Ascii85Decoder();

	virtual void decode(std::istringstream &in, std::ostringstream &out); 
};

class LzwDecoder : public _DoFileFilter
{
protected:
	class NBitInputStream
	{
	protected:
		int bitsInChunk;
		istream &in;
		int currPos;
		int currentByte;
		int bitsLeftInCurrentByte;
	public:
		NBitInputStream( istream &is );

		void unread( long data );
		
		long read();

		int getBitsInChunk();

		void setBitsInChunk(int bitsInChunkValue);
	};
	
	class LZWNode 
	{
	private:
		long code;
		std::map<unsigned char, CRefPtr< LZWNode > > subNodes;

	public:
		bool hashEqual(const CRefPtr< LZWNode > &obj) const { return false;} //dummy for use CRefPtr
		
		LZWNode( long codeValue );
		
		~LZWNode();

		int childCount();

		void setNode( unsigned char b, CRefPtr< LZWNode > );
		
		CRefPtr< LZWNode > getNode( unsigned char data );

		CRefPtr< LZWNode > getNode( unsigned char data[], int len );

		long getCode();
	};
	
	class LZWDictionary
	{
		typedef std::map<long, std::string> CodeData;
		typedef std::map<long, std::string>::iterator CodaIter;
	private:
		CodeData codeToData;
		CRefPtr< LZWNode > root, previous, current;
		long nextCode;
		int codeSize;
		std::ostringstream buffer;

	public:
		bool hashEqual(const CRefPtr< LZWDictionary > &obj) const { return false;} //dummy for use CRefPtr
	
		LZWDictionary();
		
		~LZWDictionary();
		
		std::string getData( long code );

		void visit( const unsigned char *data, int len);

		void visit( unsigned char data );

		long getNextCode();
		
		int getCodeSize();

		void resetCodeSize();

		void clear();

		CRefPtr< LZWNode > getNode( unsigned char * data, int len );

		CRefPtr< LZWNode > addRootNode( unsigned char b);
	};
	
protected:
	LzwDecoder(const LzwDecoder&);
	LzwDecoder& operator=(const LzwDecoder& obj);
public:
	LzwDecoder();
	~LzwDecoder();

	virtual void decode(std::istringstream &in, std::ostringstream &out); 
};
 
#endif /* DOFILEFILTER_H_ */
